package com.zsc.wxm.ysh.anjo.house.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.wxm.ysh.anjo.house.cache.EstateCacheService;
import com.zsc.wxm.ysh.anjo.house.cache.ResourcesCacheService;
import com.zsc.wxm.ysh.anjo.house.feign.EsService;
import com.zsc.wxm.ysh.anjo.house.mapper.ResourcesMapper;
import com.zsc.wxm.ysh.anjo.house.model.Estate;
import com.zsc.wxm.ysh.anjo.house.model.Resources;
import com.zsc.wxm.ysh.anjo.house.service.EstateService;
import com.zsc.wxm.ysh.anjo.house.service.ImagesService;
import com.zsc.wxm.ysh.anjo.house.service.ResourcesService;
import com.zsc.wxm.ysh.anjo.house.utils.CodeUtil;
import com.zsc.wxm.ysh.anjo.result.CodeEnum;
import com.zsc.wxm.ysh.anjo.result.PageResult;
import com.zsc.wxm.ysh.anjo.result.Result;
import com.zsc.wxm.ysh.anjo.service.base.config.RabbitMqConfig;
import com.zsc.wxm.ysh.anjo.service.base.enums.resources.*;
import com.zsc.wxm.ysh.anjo.service.base.exception.AnjoException;
import com.zsc.wxm.ysh.anjo.service.base.model.es.vo.EsDataVO;
import com.zsc.wxm.ysh.anjo.service.base.model.mq.MqMessage;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.dto.EstateDTO;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.dto.MyRentHouseDTO;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.dto.ResourcesDTO;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.qo.ResourcesQuery;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.vo.HouseInfoVO;
import com.zsc.wxm.ysh.anjo.service.base.model.resources.vo.ImagesVO;
import com.zsc.wxm.ysh.anjo.service.base.model.staticdata.vo.HouseInfoStaticVO;
import com.zsc.wxm.ysh.anjo.utils.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author playmaker
 * @since 2021-01-04
 */
@Service
@Slf4j
public class ResourcesServiceImpl extends ServiceImpl<ResourcesMapper, Resources> implements ResourcesService {

    @Resource
    private EstateService estateService;

    @Resource
    private ImagesService imagesService;

    @Resource
    private EsService esService;

    @Resource
    private CodeUtil codeUtil;

    @Resource
    private ResourcesCacheService resourcesCacheService;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private EstateCacheService estateCacheService;

    @Override
    public void batchAddHouseData() throws IOException {
        List<Resources> list = this.list(null);
        List<EsDataVO> esDataVos = new ArrayList<>();
        if (CollUtil.isNotEmpty(list)) {
            for (Resources resources : list) {
                EsDataVO esDataVo = initEsDataVO(resources);
                esDataVos.add(esDataVo);
            }
            esService.uploadEsData(esDataVos);
        }
        log.info("批量导入数据到es中成功");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Resources addResources(ResourcesDTO params, MultipartFile[] files) {
        Assert.isTrue(!(files == null || files.length == 0), "房源图片不能为空");
        @NotEmpty(message = "配套设施不能为空") List<String> facilitiesArray = params.getFacilitiesArray();
        if (StringUtils.isNotBlank(params.getCode())) {
            //判断房源是否重复
            LambdaQueryWrapper<Resources> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Resources::getCode, params.getCode());
            if (this.getOne(lambdaQueryWrapper) != null) {
                throw new AnjoException(CodeEnum.HOUSE_IS_EXIT);
            }
        }
        Resources resources = getNewResources(params, facilitiesArray);
        resources.setCode(codeUtil.getSquenceCode());
        this.save(resources);
        //图片上传
        imagesService.upload(resources.getId(), files);

        return resources;
    }

    private Resources getNewResources(ResourcesDTO params, @NotEmpty(message = "配套设施不能为空") List<String> facilitiesArray) {
        StringBuilder facilities = new StringBuilder();
        for (String facilitiesStr : facilitiesArray) {
            facilities.append(facilitiesStr).append(",");
        }
        log.info("配套设施的长度：{}，值：{}",facilities.toString().length(), facilities);
        params.setFacilities(facilities.toString().substring(0, facilities.toString().length() - 1));
        Resources resources = new Resources();
        BeanUtils.copyProperties(params, resources);
        log.info(resources.getFacilities());
        return resources;
    }

    @Override
    public PageResult listPage(ResourcesQuery params) {
        Page<Resources> page = new Page<>(params.getCurrPage(), params.getPageSize());
        LambdaQueryWrapper<Resources> lambdaQueryWrapper = Wrappers.lambdaQuery();
        //构造查询条件
        buildQueryParams(params, lambdaQueryWrapper);
        page = baseMapper.selectPage(page, lambdaQueryWrapper);
        PageUtil pageUtil = new PageUtil(page);
        return PageResult.ok(pageUtil.getList(), pageUtil.getTotal());
    }

    @Override
    public Result deleteById(Long id) {
        Resources resources = baseMapper.selectById(id);
        if (HouseStatus.UNAVAILABLE.getValue() == resources.getStatus()) {
            return Result.error("该房源已出租，不能删除");
        }
        baseMapper.deleteById(id);
        resourcesCacheService.removeByIdCache(id);
        resourcesCacheService.removeByIdCache(id);
        //通知ES删除数据
        rabbitTemplate.convertAndSend(RabbitMqConfig.ES_EXCHANGE,RabbitMqConfig.ES_BIND_KEY,
                new MqMessage(id, MqMessage.DELETE));
        return Result.ok("删除成功");
    }

    @Override
    public HouseInfoVO getInfoById(Long id) {
        //房源
        Resources resources = resourcesCacheService.getByIdCache(id);
        //楼盘
        Estate estate = estateService.getOneById(resources.getEstateId());
        //图片
        List<ImagesVO> images = imagesService.list(id);

        HouseInfoVO vo = new HouseInfoVO();
        BeanUtils.copyProperties(resources, vo);
        vo.setImages(images.stream().map(ImagesVO::getImageUrl).collect(Collectors.toList()));
        vo.setEstateName(estate.getName());
        vo.setAddress(estate.getAddress());
        vo.setArea(estate.getArea());
        vo.setCity(estate.getCity());
        vo.setYear(estate.getYear() + "年");
        vo.setPropertyCost(estate.getPropertyCost() + "元/月");
        vo.setPropertyCompany(estate.getPropertyCompany());
        vo.setDevelopers(estate.getDevelopers());
        vo.setProvince(estate.getProvince());
        vo.setType(estate.getType());

        vo.setRent(resources.getRent() + "元/月");
        vo.setRentMethod(RentType.getEnumDesc(resources.getRentMethod()));
        vo.setPaymentMethod(PaymentType.getEnumDesc(resources.getPaymentMethod()));
        vo.setOrientation(TowardsType.getEnumDesc(resources.getOrientation()));
        vo.setStatus(HouseStatus.getEnumDesc(resources.getStatus()));
        vo.setDecoration(WeltType.getEnumDesc(resources.getDecoration()));
        vo.setTime(ViewingTimeType.getEnumDesc(resources.getTime()));

        return vo;
    }

    @Override
    public void updateStatus(Long id, int status) {
        LambdaUpdateWrapper<Resources> wrapper = Wrappers.lambdaUpdate();
        wrapper.set(Resources::getStatus, status);
        wrapper.eq(Resources::getId, id);
        this.update(wrapper);
        resourcesCacheService.removeByIdCache(id);
        resourcesCacheService.removeByIdCache(id);
        if (HouseStatus.PASSED.getValue() == status) {
            //发送通知给ES，修改
            rabbitTemplate.convertAndSend(RabbitMqConfig.ES_EXCHANGE,RabbitMqConfig.ES_BIND_KEY,
                    new MqMessage(id, MqMessage.CREATE_OR_UPDATE));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateItem(ResourcesDTO params, MultipartFile[] files) {
        if (files != null && files.length > 0) {
            //替换图片
            imagesService.deleteImage(params.getId());
            imagesService.upload(params.getId(), files);
        }
        Resources resources = getNewResources(params, params.getFacilitiesArray());
        this.updateById(resources);
        resourcesCacheService.removeByIdCache(params.getId());
    }

    @Override
    public List<HouseInfoStaticVO> getUserHouseByNameAndPhone(Long userId) {
        List<Resources> list = resourcesCacheService.listByUserIdCache(userId);
        List<HouseInfoStaticVO> staticVos = new ArrayList<>();
        list.forEach(x -> {
            HouseInfoVO houseInfoVO = this.getInfoById(x.getId());
            HouseInfoStaticVO vo = new HouseInfoStaticVO();
            vo.setAddress(houseInfoVO.getProvince() + houseInfoVO.getCity() + houseInfoVO.getAddress());
            vo.setFacilities(x.getFacilities());
            vo.setStatus(HouseStatus.getEnumDesc(x.getStatus()));
            vo.setHouseTitle(x.getTitle());
            staticVos.add(vo);
        });
        return staticVos;
    }

    @Override
    public PageResult getMyRentHouse(MyRentHouseDTO param) {
        Page<Resources> page = new Page<>(param.getCurrPage(), param.getPageSize());
        LambdaQueryWrapper<Resources> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Resources::getPhone, param.getPhone());
        page = baseMapper.selectPage(page, wrapper);
        List<Resources> resources = page.getRecords();
        if (CollUtil.isEmpty(resources)) {
            return PageResult.ok(Collections.emptyList(), 0);
        }
        List<EsDataVO> list = new ArrayList<>();
        resources.forEach(item -> list.add(this.initEsDataVO(item)));
        PageUtil pageUtil = new PageUtil(page);
        return PageResult.ok(list, pageUtil.getTotal());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void entrustHouse(EstateDTO estateDto, ResourcesDTO resourcesDto, MultipartFile[] files) {
        //新增楼盘
        Long estateId = estateService.addEstate(estateDto);
        resourcesDto.setEstateId(estateId);
        //提交房源申请
        this.addResources(resourcesDto, files);

    }

    @Override
    public EsDataVO getEsDataVoById(Long id) {
        return this.initEsDataVO(this.getById(id));
    }

    private void buildQueryParams(ResourcesQuery params, LambdaQueryWrapper<Resources> lambdaQueryWrapper) {
        //标题
        if (StringUtils.isNotBlank(params.getTitle())) {
            lambdaQueryWrapper.like(Resources::getTitle, params.getTitle());
        }
        //联系人
        if (StringUtils.isNotBlank(params.getConstact())) {
            lambdaQueryWrapper.like(Resources::getConstact, params.getConstact());
        }
        //电话
        if (StringUtils.isNotBlank(params.getPhone())) {
            lambdaQueryWrapper.like(Resources::getPhone, params.getPhone());
        }
        //编码
        if (StringUtils.isNotBlank(params.getCode())) {
            lambdaQueryWrapper.like(Resources::getCode, params.getCode());
        }
        //最小租金
        if (StringUtils.isNotBlank(params.getMinRent())) {
            lambdaQueryWrapper.ge(Resources::getRent, new BigDecimal(params.getMinRent()));
        }
        //最大租金
        if (StringUtils.isNotBlank(params.getMaxRent())) {
            lambdaQueryWrapper.le(Resources::getRent, new BigDecimal(params.getMaxRent()));
        }
        //租赁方式
        if (params.getRentMethod() != null) {
            lambdaQueryWrapper.eq(Resources::getRentMethod, params.getRentMethod());
        }
        //看房时间
        if (params.getTime() != null) {
            lambdaQueryWrapper.eq(Resources::getTime, params.getTime());
        }
        //房源状态
        if (params.getStatus() != null) {
            if (HouseStatus.PASSED.getValue() == params.getStatus()) {
                lambdaQueryWrapper.in(Resources::getStatus, Arrays.asList(HouseStatus.AVAILABLE.getValue()
                        ,HouseStatus.UNAVAILABLE.getValue()));
            } else {
                lambdaQueryWrapper.eq(Resources::getStatus, params.getStatus());
            }
        }
        //设置关联查询条件
        buildRelationsWhere(params, lambdaQueryWrapper);
    }

    private void buildRelationsWhere(ResourcesQuery params, LambdaQueryWrapper<Resources> lambdaQueryWrapper) {
        //关联条件
        List<Long> estateIds = new ArrayList<>();
        LambdaQueryWrapper<Estate> estateLambdaQueryWrapper = Wrappers.lambdaQuery();
        //城市
        if (StringUtils.isNotBlank(params.getCity())) {
            estateLambdaQueryWrapper.like(Estate::getCity, params.getCity());
        }
        //地址
        if (StringUtils.isNotBlank(params.getAddress())) {
            estateLambdaQueryWrapper.like(Estate::getAddress, params.getAddress());
        }
        //省份
        if (StringUtils.isNotBlank(params.getProvince())) {
            estateLambdaQueryWrapper.like(Estate::getProvince, params.getProvince());
        }
        if (!estateLambdaQueryWrapper.isEmptyOfWhere()) {
            List<Estate> list = estateService.list(estateLambdaQueryWrapper);
            if (CollUtil.isNotEmpty(list)) {
                estateIds.addAll(list.stream().map(Estate::getId).collect(Collectors.toList()));
            }
        }
        if (CollUtil.isNotEmpty(estateIds)) {
            lambdaQueryWrapper.in(Resources::getEstateId, estateIds);
        }
    }

    EsDataVO initEsDataVO(Resources resources) {
        Estate estate = estateService.getOneById(resources.getEstateId());
        //数据封装
        EsDataVO esDataVo = new EsDataVO();
        esDataVo.setId(resources.getId());
        esDataVo.setTitle(resources.getTitle());
        esDataVo.setModifyTime(Date.from(resources.getModifyTime().atZone(ZoneId.systemDefault()).toInstant()));
        //图片
        ImagesVO imagesVo = imagesService.list(resources.getId()).get(0);
        esDataVo.setImage(imagesVo.getImageUrl());
        esDataVo.setRent(resources.getRent() + "");
        esDataVo.setProvince(estate.getProvince());
        esDataVo.setCity(estate.getCity());
        esDataVo.setAddress(estate.getAddress());
        esDataVo.setOrientation(TowardsType.getEnumDesc(resources.getOrientation()));
        esDataVo.setPayType(PaymentType.getEnumDesc(resources.getPaymentMethod()));
        esDataVo.setStatus(HouseStatus.getEnumDesc(resources.getStatus()));
        return esDataVo;
    }
}
